package com.atguigu.dga.governance.assessor.security;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.atguigu.dga.governance.assessor.Assessor;
import com.atguigu.dga.governance.bean.AssessParam;
import com.atguigu.dga.governance.bean.GovernanceAssessDetail;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.fs.permission.FsPermission;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.math.BigDecimal;
import java.net.URI;
import java.net.URISyntaxException;
import java.text.ParseException;
import java.util.ArrayList;

/**
 * ClassName: TableDirFilePermissionAssessor
 * Package: com.atguigu.dga.governance.assessor.security
 * Description:
 *
 * @Author:
 * @Create: 2024/3/19 10:20
 * @Version: 1.0
 */
@Component("TABLE_DIR_FILE_PERMISSION")
public class TableDirFilePermissionAssessor extends Assessor {
    @Value("${hdfs.uris}")
    private String hdfsUris;
    @Override
    public void checkProblem(AssessParam assessParam, GovernanceAssessDetail governanceAssessDetail) throws URISyntaxException, IOException, InterruptedException {
        // 判断当前表路径下 所有的文件和目录 是否超过指标参数建议值
        // TODO 1 指标参数
        String metricParamsJson = assessParam.getGovernanceMetric().getMetricParamsJson();
        JSONObject paramJsonObj = JSON.parseObject(metricParamsJson);
        String paramFilePermission = paramJsonObj.getString("file_permission");
        String paramDirPermission = paramJsonObj.getString("dir_permission");

        // TODO 2 表路径
        String tableFsPath = assessParam.getTableMetaInfo().getTableFsPath();
        tableFsPath = tableFsPath.replace("hadoop102:8020", "localhost:18020");
        FileSystem fs = FileSystem.get(new URI(hdfsUris), new Configuration(), assessParam.getTableMetaInfo().getTableFsOwner());

        // TODO 3 文件对象创建 检查路径下所有目录和文件， 越权的文件和目录记录下来
        FileStatus[] fileStatuses = fs.listStatus(new Path(tableFsPath));
        ArrayList<String> beyondDirList = new ArrayList<>();
        ArrayList<String> beyondFileList = new ArrayList<>();

        // TODO 4 调用封装的判断方法
        checkDirOrFilePermission(fileStatuses, fs, beyondDirList,beyondFileList,paramFilePermission,paramDirPermission);

        //  判断
        if (!beyondFileList.isEmpty() || !beyondDirList.isEmpty()) {
            governanceAssessDetail.setAssessScore(BigDecimal.ZERO);
            governanceAssessDetail.setAssessProblem("目录或文件越权");
            governanceAssessDetail.setAssessComment("越权目录: " + beyondDirList + " , 越权文件: " + beyondFileList);
        }


    }



    // TODO 4 封装检查方法
    private void checkDirOrFilePermission(FileStatus[] fileStatuses, FileSystem fs,
                                          ArrayList<String> beyondDirList, ArrayList<String> beyondFileList ,
                                          String paramFilePermission , String paramDirPermission) throws IOException {
        for (FileStatus fileStatus : fileStatuses) {
            if(fileStatus.isFile()) {
                // 文件
                FsPermission filePermission = fileStatus.getPermission();
                boolean isBeyond = checkRWX(filePermission, paramFilePermission);
                if(isBeyond) {
                    beyondFileList.add(fileStatus.getPath().getName());
                }

            }else {
                // 目录是否越权
                FsPermission dirPermission = fileStatus.getPermission();
                boolean isBeyond = checkRWX(dirPermission, paramDirPermission);
                if(isBeyond) {
                    beyondDirList.add(fileStatus.getPath().getName());
                }

                // 获取当前目录下的所有内容
                FileStatus[] subFileStatuses = fs.listStatus(fileStatus.getPath());
                checkDirOrFilePermission(subFileStatuses,fs,
                        beyondDirList,beyondFileList,
                        paramFilePermission,paramDirPermission);

            }
        }
    }

    // TODO 4-1 比较ugo
    private boolean checkRWX(FsPermission filePermission, String paramFilePermission) {
       int paramUser = paramFilePermission.charAt(0) - '0';
       int paramGroup = paramFilePermission.charAt(1) - '0';
       int paramOther = paramFilePermission.charAt(2) - '0';

       if(filePermission.getUserAction().ordinal() > paramUser) {
           return true;
       } else if (filePermission.getGroupAction().ordinal() > paramGroup) {
           return true;
       } else if (filePermission.getOtherAction().ordinal() > paramOther) {
           return true;
       }
        return false;
    }

}
